package com.xzy.learn.spring.bean.destroy;

import com.xzy.learn.spring.bean.destroy.bean.StudentE;
import com.xzy.learn.spring.bean.destroy.bean.StudentF;
import com.xzy.learn.spring.bean.destroy.bean.StudentG;
import com.xzy.learn.spring.bean.destroy.bean.StudentH;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 销毁 Bean 的方式
 *
 * @author xzy.xiao
 * @date 2022/6/2  10:44
 */
public class DestroyBeanDemo {

    public static void main(String[] args) {
        destroyByPreDestroyAnnotation();
//        destroyByDisposableBeanInterface();
//        destroyByDestroyMethod();
//        test();
    }

    /**
     * 销毁方式：通过 @PreDestroy 注解标注的方法
     */
    public static void destroyByPreDestroyAnnotation() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(StudentE.class);
        annotationConfigApplicationContext.refresh();

        StudentE bean = annotationConfigApplicationContext.getBean(StudentE.class);
        System.out.println(bean);

        System.out.println("上下文准备关闭...");
        annotationConfigApplicationContext.close();
        System.out.println("上下文已经关闭...");
    }

    /**
     * 销毁方式：通过实现 DisposableBean 接口的 destroy() 方法
     */
    public static void destroyByDisposableBeanInterface() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(StudentF.class);
        annotationConfigApplicationContext.refresh();

        StudentF bean = annotationConfigApplicationContext.getBean(StudentF.class);
        System.out.println(bean);

        System.out.println("上下文准备关闭...");
        annotationConfigApplicationContext.close();
        System.out.println("上下文已经关闭...");
    }

    /**
     * 销毁方式：通过自定义的销毁方法
     */
    public static void destroyByDestroyMethod() {
//        setDestroyMethodByBeanDefinition();
        setDestroyMethodByBeanConfig();
    }

    private static void setDestroyMethodByBeanDefinition() {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(StudentG.class);
        beanDefinitionBuilder.setDestroyMethodName("myDestroy");

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.registerBeanDefinition("studentG", beanDefinitionBuilder.getBeanDefinition());
        annotationConfigApplicationContext.refresh();

        StudentG bean = annotationConfigApplicationContext.getBean(StudentG.class);
        System.out.println(bean);

        System.out.println("上下文准备关闭...");
        annotationConfigApplicationContext.close();
        System.out.println("上下文已经关闭...");
    }

    private static void setDestroyMethodByBeanConfig() {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-destroy.xml");

        StudentG bean = classPathXmlApplicationContext.getBean(StudentG.class);
        System.out.println(bean);

        System.out.println("上下文准备关闭...");
        classPathXmlApplicationContext.close();
        System.out.println("上下文已经关闭...");

        /*
         * 配置 Bean 的方式：
         * 1、<bean destroy-method=""/>
         * 2、@Bean(destroyMethod="")
         */
    }

    /**
     * 测试：如果同时配置了多种销毁方式，它们的执行顺序是怎么样的？
     */
    private static void test() {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(StudentH.class);
        beanDefinitionBuilder.setDestroyMethodName("myDestroy");
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.registerBeanDefinition("studentH", beanDefinition);
        annotationConfigApplicationContext.refresh();

        StudentH bean = annotationConfigApplicationContext.getBean(StudentH.class);
        System.out.println(bean);

        System.out.println("上下文准备关闭...");
        annotationConfigApplicationContext.close();
        System.out.println("上下文已经关闭...");
    }
}
